
@import 'config'

/*
 * Replace the given str with val in the expr.
 */

replace(expr, str, val)
  expr = clone(expr)
  for e, i in expr
    if length(e) > 1
      expr[i] = replace(e, str, val)
    else
      if str == e
        expr[i] = val
  expr

/*
 * Normalize gradient points.
 */

grad-point(pos)
  if length(pos) == 1
    return left pos if pos in (top bottom)
    return pos top if pos in (left right)
  else if pos[0] in (top bottom)
    pos[1] pos[0]
  else
    pos

/*
 * Implicit color stop position.
 */

pos-in-stops(i, stops)
  len = length(stops)
  if len - 1 == i
    100%
  else if i
    unit(i / len * 100, '%')
  else
    0%

/*
 * Normalize color stops:
 * 
 *   - (color pos) -> (pos color)
 *   - (color) -> (implied-pos color)
 * 
 */

normalize-stops(stops)
  stops = clone(stops)
  for stop, i in stops
    if length(stop) == 1
      color = stop[0]
      stop[0] = pos-in-stops(i, stops)
      stop[1] = color
    else if typeof(stop[1]) == 'unit'
      pos = stop[1]
      stop[1] = stop[0]
      stop[0] = pos
  stops

/*
 * Join color stops with the given translation function.
 */

join-stops(stops, translate)
  str = ''
  len = length(stops)
  for stop, i in stops
    str += ', ' if i
    pos = stop[0]
    color = stop[1]
    str += translate(color, pos)
  unquote(str)

/*
 * Legacy Webkit color stop.
 */

webkit-stop(color, pos)
  'color-stop(%d, %s)' % (pos / 100 color)

/*
 * Standard color stop.
 */

std-stop(color, pos)
  '%s %s' % (color pos) 

/*
 * Create a linear gradient with the given start position
 * and variable number of color stops.
 * 
 * Examples:
 * 
 *    background: linear-gradient(top, red, green, blue)
 *    background: linear-gradient(bottom, red, green 50%, blue)
 *    background: linear-gradient(bottom, red, 50% green, blue)
 *    background: linear-gradient(bottom, red, 50% green, 90% white, blue)
 * 
 */

linear-gradient(start, stops...)
  error('color stops required') unless length(stops)
  prop = current-property[0]
  val = current-property[1]
  stops = normalize-stops(stops)

  // gradient image
  if start[0] is a 'unit'
    if has-canvas
      img = linear-gradient-image(start, stops)
      add-property(prop, replace(val, '__CALL__', img))
    start = start[1]

  // legacy webkit
  end = grad-point(opposite-position(start))
  webkit-legacy = '-webkit-gradient(linear, %s, %s, %s)' % (grad-point(start) end join-stops(stops, webkit-stop))
  add-property(prop, replace(val, '__CALL__', webkit-legacy))

  // vendor prefixed
  stops = join-stops(stops, std-stop)
  for prefix in vendor-prefixes
    unless prefix == official
      gradient = '-%s-linear-gradient(%s, %s)' % (prefix start stops)   
      add-property(prop, replace(val, '__CALL__', gradient))

  // standard 
  'linear-gradient(%s, %s)' % (start stops)

/*
 * Create a linear gradient image with the given start position
 * and variable number of color stops.
 */

linear-gradient-image(start, stops...)
  error('node-canvas is required for linear-gradient-image()') unless has-canvas
  stops = stops[0] if length(stops) == 1
  error('gradient image size required') unless start[0] is a 'unit'
  size = start[0]
  start = start[1] or 'top'
  grad = create-gradient-image(size, start)
  stops = normalize-stops(stops)
  add-color-stop(grad, stop[0], stop[1]) for stop in stops
  'url(%s)' % gradient-data-uri(grad)
